
from game.object.obj_model import ObjectModel
from OpenGL.GL import *
import os
import pygame
from pygame.locals import *

class ResourceManager:

    def __init__(self):
        self.terrain_objs = {}


    def load_terrain(self, terrain_id):
        """
        This method will retrieve an obj for a given terrain_id
        If the texture does not yet exist, it will load the texture
        """

        if terrain_id not in self.terrain_objs:
            fpath = os.path.join('data', 'client', 'models', 'terrain')
            fname = '{0}.obj'.format(terrain_id)
            o = self.load_obj(fpath, fname)
            if o is None:
                raise Error('Trying to load non-existing terrain texture: {0}'.format(terrain_id))

            self.terrain_objs[terrain_id] = o
            
        return self.terrain_objs[terrain_id]


    def load_obj(self, fpath, fname, swapyz=0):
        file = open(os.path.join(fpath, fname), 'r')
        obj = ObjectModel()
        material = None
        for line in file:
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'v':
                v = map(float, values[1:4])
                if swapyz:
                    v = v[0], v[2], v[1]
                obj.vertices.append(v)
            elif values[0] == 'vn':
                v = map(float, values[1:4])
                if swapyz:
                    v = v[0], v[2], v[1]
                obj.normals.append(v)
            elif values[0] == 'vt':
                obj.texcoords.append(map(float, values[1:3]))
            elif values[0] in ('usemtl', 'usemat'):
                material = values[1]
            elif values[0] == 'mtllib':
                obj.mtl = self.load_material(fpath, values[1])
            elif values[0] == 'f':
                face = []
                texcoords = []
                norms = []
                for v in values[1:]:
                    w = v.split('/')
                    face.append(int(w[0]))
                    if len(w) >= 2 and len(w[1]) > 0:
                        texcoords.append(int(w[1]))
                    else:
                        texcoords.append(0)
                    if len(w) >= 3 and len(w[2]) > 0:
                        norms.append(int(w[2]))
                    else:
                        norms.append(0)
                obj.faces.append((face, norms, texcoords, material))

        obj.display_list = glGenLists(1)
        glNewList(obj.display_list, GL_COMPILE)
        glFrontFace(GL_CCW)
        for face in obj.faces:
            vertices, normals, texture_coords, material = face
            mtl = obj.mtl[material]
            if 'texture_Kd' in mtl:
                # use diffuse texmap
                glEnable(GL_TEXTURE_2D)
                glBindTexture(GL_TEXTURE_2D, mtl['texture_Kd'])
            else:
                # just use diffuse colour
                glColor(*mtl['Kd'])

            #glBegin(GL_POLYGON) #for solid
            glBegin(GL_LINE_LOOP) #for wireframe
            for i in range(len(vertices)):
                if normals[i] > 0:
                    glNormal3fv(obj.normals[normals[i] - 1])
                if texture_coords[i] > 0:
                    glTexCoord2fv(obj.texcoords[texture_coords[i] - 1])
                glVertex3fv(obj.vertices[vertices[i] - 1])
            glEnd()

            if 'texture_Kd' in mtl:
                glDisable(GL_TEXTURE_2D)
        glEndList()

        return obj

    def load_material(self, fpath, fname):
        file = open(os.path.join(fpath, fname), 'r')
        contents = {}
        mtl = None
        for line in file:
            if line.startswith('#'): continue
            values = line.split()
            if not values: continue
            if values[0] == 'newmtl':
                mtl = contents[values[1]] = {}
            elif mtl is None:
                raise ValueError, "mtl file doesn't start with newmtl stmt"
            elif values[0] == 'map_Kd':
                # load the texture referred to by this declaration
                mtl[values[0]] = values[1]
                surf = pygame.image.load(os.path.join(fpath, mtl['map_Kd']))
                image = pygame.image.tostring(surf, 'RGBA', 1)
                ix, iy = surf.get_rect().size
                texid = mtl['texture_Kd'] = glGenTextures(1)
                glBindTexture(GL_TEXTURE_2D, texid)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                    GL_LINEAR)
                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                    GL_LINEAR)
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ix, iy, 0, GL_RGBA,
                    GL_UNSIGNED_BYTE, image)
            else:
                mtl[values[0]] = map(float, values[1:])
        return contents

